package com.ophiux.utils.wechat;

import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import javax.xml.parsers.ParserConfigurationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

/**
 * @Auther: liyang
 * @Date: 2019/6/10 11:51
 * @Description:
 */
public class JDSSignature {
	private static final Logger log = LoggerFactory.getLogger(JDSSignature.class);
	public static final String SIGN_ALGORITHMS = "SHA1WithRSA";

	/**
	 * 签名算法( HMACSHA256加密签名算法,传入参数是集合)
	 * 
	 * @param parameters
	 * @param key
	 * @return
	 */
	public static String createSign(String pkcs1PrivateKey,String key,Map<String, Object> parameters) {
		StringBuilder sb = new StringBuilder();
		Map<String, Object> treeMap = new TreeMap<String, Object>(parameters);
		for (Map.Entry<String, Object> m : treeMap.entrySet()) {
			if (m.getValue() == null || "".equals(m.getValue().toString().trim()) || "sign".equals(m.getKey())
					|| "key".equals(m.getKey()) || "transaction_swift_number".equals(m.getKey()) || "mch_token".equals(m.getKey()) || "pay_way".equals(m.getKey())
					|| "serialVersionUID".equals(m.getKey())) {
				continue;
			}
			//给金额2.3元转为2.30元
			if("total_amount".equals(m.getKey())||"pay_amount".equals(m.getKey())||"order_amount".equals(m.getKey())) {
				DecimalFormat df = new DecimalFormat("0.00"); 
				String value = df.format(m.getValue());
				sb.append(m.getKey()).append("=").append(value).append("&");
				continue;
			}
			sb.append(m.getKey()).append("=").append(m.getValue()).append("&");
		}
		sb.append("key=").append(key);
		System.out.println("签名字符串:" + sb);
		String encodesign = "";
		try {
			// HMACSHA256加密
			String MHACsign = HMACSHA256.sha256_HMAC(sb.toString(), key).toUpperCase();// 转换成大写
			System.out.println("签名hmac:" + MHACsign);
			// RSAq 签名
			String sign = RSA.sign(MHACsign, pkcs1PrivateKey);
			System.out.println("rsa签名："+sign);
			// URL编码
			encodesign = URLEncoder.encode(sign, "UTF-8");
			System.out.println("encodesign签名："+encodesign);

		} catch (Exception e) {
			e.printStackTrace();
		}

		return encodesign;
	}

	/**
	 * 检验API返回的数据里面的签名是否合法，避免数据在传输的过程中被第三方篡改
	 * 
	 * @return API签名是否合法
	 * @throws ParserConfigurationException
	 * @throws IOException
	 * @throws SAXException
	 */
	public static boolean checkSign(String pkcs1PublicKey,String key,Map<String, Object> map) throws Exception {

		StringBuilder s = new StringBuilder();
		Map<String, Object> treeMap = new TreeMap<String, Object>(map);
		for (Map.Entry<String, Object> m : treeMap.entrySet()) {
			if (m.getValue() == null || "".equals(m.getValue().toString().trim()) || "sign".equals(m.getKey())
					|| "key".equals(m.getKey()) || "transaction_swift_number".equals(m.getKey())
					|| "serialVersionUID".equals(m.getKey()))
				continue;
			s.append(m.getKey()).append("=").append(m.getValue()).append("&");
		}
		s.append("key=").append(key);
		log.info("验证签名字符串: " + s);
		System.out.println("验证签名字符串:" + s);
		String MHACsign = HMACSHA256.sha256_HMAC(s.toString(), key).toUpperCase();
		System.out.println("签名hmac:" + MHACsign);
		System.out.println("获取的签名:" + map.get("sign"));
		String signFromAPIResponse = URLDecoder.decode(map.get("sign").toString(), "UTF-8");
		System.out.println("返回参数signFromAPIResponse的签名:" + signFromAPIResponse);
		if (signFromAPIResponse == "" || signFromAPIResponse == null) {
			log.info("API返回的数据签名数据不存在，有可能被第三方篡改!!!");
			return false;
		}
		log.info("服务器回包里面的签名是:" + signFromAPIResponse);

		if (RSA.verify(MHACsign, signFromAPIResponse, pkcs1PublicKey)) {
			log.info("恭喜，API返回的数据签名验证通过!!!");
			return true;
		}

		return false;
	}
	public static void main(String[] args) throws Exception {
		Map<String, Object> map = new HashMap<>();
		map.put("jds_org_id", "80160100000000012495");
		map.put("extend_params", "");
		map.put("nonce_str", "CCGSPd1wFchr1zIwYDWd8hcboBzhVNGq");
		map.put("time_expire", "");
		map.put("operator_id", "4001");
		map.put("latitude", "null");
		map.put("discount_details", "[]");
		map.put("sign",
				"Wg5v2hd4rJicCF6MXJQCuTfkhx5aSNc8nIoI7nW4AR3Dgp4OX5QFj0Ynp1c/3o+9iALlYKCLIp5GJC74pEQNypVLdhns5zHffEyip/SWVvNDgggDhSHUG4kyuxJHLFBDwMVp6m1dLfOR2cK4nWAk8hqMj4AdCWYL0FT7Bm17UeNvusAGXloRs3T+KE5ycUlnvJqdla9GUtm3uGzS/6LELCAUGsCwHWfS2K1kqS8Dv6Wmlyw0UeCmGq2ksrxor2xUIfUTrjw9HTZNUfHYS2DNj/gXAp691Nml12LUVaB7MWWTqDSDu2NtGT7bMSkjKOVfzaDi2lwR25K/IdTRfRlUnA==");
		map.put("device_type", "JDS_JJY_ERP_A8");
		map.put("remark", "null");
		map.put("recharge_detail", "null");
		map.put("body", "郑州香衣丽橱服饰商行");
		map.put("mch_id", "16160900010105803700501");
		map.put("fund_bill_list", "[]");
		map.put("scene", "bar_code");
		map.put("serialVersionUID", "1");
		map.put("member_card_id", "15238875580");
		map.put("goods_tag", "");
		map.put("order_amount", "0.01");
		map.put("fingerprint", "");
		map.put("limit_pay", "");
		map.put("attach", "服饰");
		map.put("channel_type", "WX");
		map.put("third_trade_no", "00002201902111729394726008306");
		map.put("longitude", "null");
		map.put("store_id", "B010002");
		map.put("create_time", "2019021615554567");
		map.put("device_id", "00002");
		map.put("member_user_id", "HY00020370");
		map.put("pay_amount", "0.01");
		map.put("device_inf", "null");
		map.put("goods_detail", "[]");
		map.put("version", "1.0");
		map.put("auth_code", "134650840580584193");
		map.put("discountable_amount", "0.00");
		map.put("voucher_detail_list", "[]");
		map.put("out_trade_no", "7c05e5faa8f04e958d2acd21ad75b8x9");
		map.put("total_amount", "0.01");
		map.put("service", "pay.jds.authpay");
		map.put("trade_type", "Consume");
		map.put("detail", "");
		map.put("device_create_ip", "117.136.44.59");
		map.put("undiscountable_amount", "0.01");
		map.put("scene_info", "");
		map.put("transaction_swift_number", "D41C4E3E5EBE4863A84F2473888B8D37");
		String sign = createSign("","",map);
		map.put("sign", sign);
		boolean b = checkSign("","",map);
		System.out.println(b);
	}
}
